package com.zgis.module.db.service;

import cn.hutool.core.collection.CollUtil;
import com.zgis.module.bas.bean.CxEntity;
import com.zgis.module.bas.bean.CxFld;
import com.zgis.module.bas.bean.CxSqlExp;
import com.zgis.module.bas.bean.CxSqlPro;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Redis缓存服务 - 用于从Redis获取cx_entity、cx_fld、cx_sqlexp等表数据
 */
@Slf4j
@Service
public class RedisCacheService {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    private static final String CACHE_KEY_ENTITY = "CxEntity";
    private static final String CACHE_KEY_FLD = "CxFld";
    private static final String CACHE_KEY_SQLEXP = "CxSqlExp";
    private static final String CACHE_KEY_SQLPRO = "CxSqlPro";

    /**
     * 根据major和minor获取Entity对象
     */
    @SuppressWarnings("unchecked")
    public CxEntity getEntityByMajorMinor(String major, String minor) {
        try {
            List<Map<String, Object>> data = (List<Map<String, Object>>) redisTemplate.opsForValue().get(CACHE_KEY_ENTITY);
            if (CollUtil.isEmpty(data)) {
                log.warn("[RedisCacheService] CxEntity缓存为空");
                return null;
            }

            return data.stream()
                    .filter(map -> {
                        Object majorObj = map.get("major");
                        Object minorObj = map.get("minor");
                        return majorObj != null && minorObj != null 
                                && majorObj.toString().equals(major)
                                && minorObj.toString().equals(minor);
                    })
                    .findFirst()
                    .map(this::mapToEntity)
                    .orElse(null);
        } catch (Exception e) {
            log.error("[RedisCacheService] 获取Entity失败, major={}, minor={}", major, minor, e);
            return null;
        }
    }

    /**
     * 根据表名获取Entity对象
     */
    @SuppressWarnings("unchecked")
    public CxEntity getEntityByName(String name) {
        try {
            List<Map<String, Object>> data = (List<Map<String, Object>>) redisTemplate.opsForValue().get(CACHE_KEY_ENTITY);
            if (CollUtil.isEmpty(data)) {
                log.warn("[RedisCacheService] CxEntity缓存为空");
                return null;
            }

            return data.stream()
                    .filter(map -> name.equals(map.get("name")))
                    .findFirst()
                    .map(this::mapToEntity)
                    .orElse(null);
        } catch (Exception e) {
            log.error("[RedisCacheService] 获取Entity失败, name={}", name, e);
            return null;
        }
    }

    /**
     * 根据表名获取字段列表
     */
    @SuppressWarnings("unchecked")
    public List<CxFld> getFldListByTableName(String tableName) {
        try {
            List<Map<String, Object>> data = (List<Map<String, Object>>) redisTemplate.opsForValue().get(CACHE_KEY_FLD);
            if (CollUtil.isEmpty(data)) {
                log.warn("[RedisCacheService] CxFld缓存为空");
                return CollUtil.newArrayList();
            }

            return data.stream()
                    .filter(map -> tableName.equals(map.get("tabname")))
                    .map(this::mapToFld)
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.error("[RedisCacheService] 获取Fld列表失败, tableName={}", tableName, e);
            return CollUtil.newArrayList();
        }
    }

    /**
     * 根据name获取SqlExp对象
     */
    @SuppressWarnings("unchecked")
    public CxSqlExp getSqlExpByName(String name) {
        try {
            List<Map<String, Object>> data = (List<Map<String, Object>>) redisTemplate.opsForValue().get(CACHE_KEY_SQLEXP);
            if (CollUtil.isEmpty(data)) {
                log.warn("[RedisCacheService] CxSqlExp缓存为空");
                return null;
            }

            return data.stream()
                    .filter(map -> name.equals(map.get("name")))
                    .findFirst()
                    .map(this::mapToSqlExp)
                    .orElse(null);
        } catch (Exception e) {
            log.error("[RedisCacheService] 获取SqlExp失败, name={}", name, e);
            return null;
        }
    }

    /**
     * 根据name获取SqlPro对象
     */
    @SuppressWarnings("unchecked")
    public CxSqlPro getSqlProByName(String name) {
        try {
            List<Map<String, Object>> data = (List<Map<String, Object>>) redisTemplate.opsForValue().get(CACHE_KEY_SQLPRO);
            if (CollUtil.isEmpty(data)) {
                log.warn("[RedisCacheService] CxSqlPro缓存为空");
                return null;
            }

            return data.stream()
                    .filter(map -> name.equals(map.get("name")))
                    .findFirst()
                    .map(this::mapToSqlPro)
                    .orElse(null);
        } catch (Exception e) {
            log.error("[RedisCacheService] 获取SqlPro失败, name={}", name, e);
            return null;
        }
    }

    /**
     * Map转Entity对象
     */
    private CxEntity mapToEntity(Map<String, Object> map) {
        return CxEntity.builder()
                .id(getLong(map, "id"))
                .name(getString(map, "name"))
                .namec(getString(map, "namec"))
                .type(getInteger(map, "type"))
                .major(getInteger(map, "major"))
                .minor(getInteger(map, "minor"))
                .domains(getInteger(map, "domains"))
                .tabgrp(getString(map, "tabgrp"))
                .glmaj(getInteger(map, "glmaj"))
                .glmin(getInteger(map, "glmin"))
                .log(getInteger(map, "log"))
                .loc(getString(map, "loc"))
                .build();
    }

    /**
     * Map转Fld对象
     */
    private CxFld mapToFld(Map<String, Object> map) {
        return CxFld.builder()
                .id(getLong(map, "id"))
                .sys(getString(map, "sys"))
                .tabname(getString(map, "tabname"))
                .colname(getString(map, "colname"))
                .namec(getString(map, "namec"))
                .isnum(getInteger(map, "isnum"))
                .disporder(getInteger(map, "disporder"))
                .disptype(getInteger(map, "disptype"))
                .newedit(getInteger(map, "newedit"))
                .editable(getInteger(map, "editable"))
                .nullable(getInteger(map, "nullable"))
                .defval(getString(map, "defval"))
                .build();
    }

    /**
     * Map转SqlExp对象
     */
    private CxSqlExp mapToSqlExp(Map<String, Object> map) {
        return CxSqlExp.builder()
                .id(getLong(map, "id"))
                .name(getString(map, "name"))
                .tab(getString(map, "tab"))
                .tables(getString(map, "tables"))
                .exp(getString(map, "exp"))
                .types(getString(map, "types"))
                .vals(getString(map, "vals"))
                .cols(getString(map, "cols"))
                .sep(getString(map, "sep"))
                .memo(getString(map, "memo"))
                .build();
    }

    /**
     * Map转SqlPro对象
     */
    private CxSqlPro mapToSqlPro(Map<String, Object> map) {
        return CxSqlPro.builder()
                .id(getLong(map, "id"))
                .name(getString(map, "name"))
                .pro(getString(map, "pro"))
                .tab(getString(map, "tab"))
                .types(getString(map, "types"))
                .vals(getString(map, "vals"))
                .cols(getString(map, "cols"))
                .sep(getString(map, "sep"))
                .oper(getString(map, "oper"))
                .build();
    }

    private String getString(Map<String, Object> map, String key) {
        Object value = map.get(key);
        return value != null ? value.toString() : null;
    }

    private Integer getInteger(Map<String, Object> map, String key) {
        Object value = map.get(key);
        if (value == null) return null;
        if (value instanceof Integer) return (Integer) value;
        try {
            return Integer.parseInt(value.toString());
        } catch (NumberFormatException e) {
            return null;
        }
    }

    private Long getLong(Map<String, Object> map, String key) {
        Object value = map.get(key);
        if (value == null) return null;
        if (value instanceof Long) return (Long) value;
        try {
            return Long.parseLong(value.toString());
        } catch (NumberFormatException e) {
            return null;
        }
    }
}
